In [1]:
import os
import numpy as np
import pandas as pd
from math import floor, ceil
from bisect import bisect_left, bisect_right
import plotly.express as px
import plotly.graph_objects as go
In [2]:
# Get data path
data_path = f"{os.path.dirname(os.getcwd())}/data"
print(data_path)
/Users/shawnguyen/Desktop/national-exam-scores-visuals/ds/data
In [3]:
# Read grades
grades = {}
for year in range(2018, 2022):
  grades[year] = pd.read_csv(f'{data_path}/diemthi{year}.csv')
  grades[year] = grades[year][["ID", "CityCode", "CityArea", "Math", "Literature", "English", "Physics", "Chemistry", "Biology", "Geography", "History", "Civic Education"]]
display(grades[2021])
ID CityCode CityArea Math Literature English Physics Chemistry Biology Geography History Civic Education
0 1000001 1 1.0 2.2 3.50 NaN NaN NaN NaN 5.50 2.50 NaN
1 1000002 1 1.0 9.2 8.25 10.0 NaN NaN NaN 9.75 5.75 9.25
2 1000003 1 1.0 4.4 6.25 NaN NaN NaN NaN 4.00 4.25 NaN
3 1000004 1 1.0 8.4 6.75 10.0 4.00 3.00 3.50 NaN NaN NaN
4 1000005 1 1.0 8.8 8.25 9.4 8.25 5.75 5.25 NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ...
1002265 64006834 64 6.0 8.6 8.25 6.2 8.25 7.00 6.50 NaN NaN NaN
1002266 64006835 64 6.0 9.0 7.50 9.4 8.00 8.25 5.50 NaN NaN NaN
1002267 64006836 64 6.0 4.8 7.00 4.6 NaN NaN NaN 7.00 3.75 9.00
1002268 64006837 64 6.0 7.4 7.75 9.4 NaN NaN NaN 6.75 4.50 9.25
1002269 64006838 64 6.0 8.0 7.75 8.2 NaN NaN NaN 6.50 4.25 7.50

1002270 rows × 12 columns

In [4]:
# Declare subjects combination
sbs = {}
sbs['A00'] = ["Math", "Physics", "Chemistry"]
sbs['A01'] = ["Math", "Physics", "English"]
sbs['A02'] = ["Math", "Physics", "Biology"]
sbs['A03'] = ["Math", "Physics", "History"]
sbs['A04'] = ["Math", "Physics", "Geography"]
sbs['A05'] = ["Math", "Chemistry", "History"]
sbs['A06'] = ["Math", "Chemistry", "Geography"]
sbs['A07'] = ["Math", "History", "Geography"]
sbs['A08'] = ["Math", "History", "Civic Education"]
sbs['A09'] = ["Math", "Geography", "Civic Education"]
sbs['A10'] = ["Math", "Physics", "Civic Education"]
sbs['A11'] = ["Math", "Chemistry", "Civic Education"]
sbs['B00'] = ["Math", "Chemistry", "Biology"]
sbs['B01'] = ["Math", "Biology", "History"]
sbs['B02'] = ["Math", "Biology", "Geography"]
sbs['B03'] = ["Math", "Biology", "Literature"]
sbs['B04'] = ["Math", "Biology", "Civic Education"]
sbs['B08'] = ["Math", "Biology", "English"]
sbs['C00'] = ["Literature", "History", "Geography"]
sbs['C01'] = ["Literature", "Math", "Physics"]
sbs['C02'] = ["Literature", "Math", "Chemistry"]
sbs['C03'] = ["Literature", "Math", "History"]
sbs['C04'] = ["Literature", "Math", "Geography"]
sbs['C05'] = ["Literature", "Physics", "Chemistry"]
sbs['C06'] = ["Literature", "Physics", "Biology"]
sbs['C07'] = ["Literature", "Physics", "History"]
sbs['C08'] = ["Literature", "Chemistry", "Biology"]
sbs['C09'] = ["Literature", "Physics", "Geography"]
sbs['C10'] = ["Literature", "Chemistry", "History"]
sbs['C12'] = ["Literature", "Biology", "History"]
sbs['C13'] = ["Literature", "Biology", "Geography"]
sbs['C14'] = ["Literature", "Math", "Civic Education"]
sbs['C16'] = ["Literature", "Physics", "Civic Education"]
sbs['C17'] = ["Literature", "Chemistry", "Civic Education"]
sbs['C19'] = ["Literature", "History", "Civic Education"]
sbs['C20'] = ["Literature", "Geography", "Civic Education"]
sbs['D01'] = ["Literature", "Math", "English"]
sbs['D07'] = ["Math", "Chemistry", "English"]
sbs['D08'] = ["Math", "Biology", "English"]
sbs['D09'] = ["Math", "History", "English"]
sbs['D10'] = ["Math", "Geography", "English"]
sbs['D11'] = ["Literature", "Physics", "English"]
sbs['D12'] = ["Literature", "Chemistry", "English"]
sbs['D13'] = ["Literature", "Biology", "English"]
sbs['D14'] = ["Literature", "History", "English"]
sbs['D15'] = ["Literature", "Geography", "English"]
sbs['D66'] = ["Literature", "Civic Education", "English"]
sbs['D84'] = ["Math", "Civic Education", "English"]
sbs['A00-Math'] = ["Math", "Physics", "Chemistry", "Math"]
sbs['A01-Math'] = ["Math", "Physics", "English", "Math"]
sbs['A02-Math'] = ["Math", "Physics", "Biology", "Math"]
sbs['A03-Math'] = ["Math", "Physics", "History", "Math"]
sbs['A04-Math'] = ["Math", "Physics", "Geography", "Math"]
sbs['A05-Math'] = ["Math", "Chemistry", "History", "Math"]
sbs['A06-Math'] = ["Math", "Chemistry", "Geography", "Math"]
sbs['A07-Math'] = ["Math", "History", "Geography", "Math"]
sbs['A08-Math'] = ["Math", "History", "Civic Education", "Math"]
sbs['A09-Math'] = ["Math", "Geography", "Civic Education", "Math"]
sbs['A10-Math'] = ["Math", "Physics", "Civic Education", "Math"]
sbs['A11-Math'] = ["Math", "Chemistry", "Civic Education", "Math"]
sbs['B00-Math'] = ["Math", "Chemistry", "Biology", "Math"]
sbs['B01-Math'] = ["Math", "Biology", "History", "Math"]
sbs['B02-Math'] = ["Math", "Biology", "Geography", "Math"]
sbs['B03-Math'] = ["Math", "Biology", "Literature", "Math"]
sbs['B04-Math'] = ["Math", "Biology", "Civic Education", "Math"]
sbs['B08-Math'] = ["Math", "Biology", "English", "Math"]
sbs['C00-Math'] = ["Literature", "History", "Geography", "Math"]
sbs['C01-Math'] = ["Literature", "Math", "Physics", "Math"]
sbs['C02-Math'] = ["Literature", "Math", "Chemistry", "Math"]
sbs['C03-Math'] = ["Literature", "Math", "History", "Math"]
sbs['C04-Math'] = ["Literature", "Math", "Geography", "Math"]
sbs['C05-Math'] = ["Literature", "Physics", "Chemistry", "Math"]
sbs['C06-Math'] = ["Literature", "Physics", "Biology", "Math"]
sbs['C07-Math'] = ["Literature", "Physics", "History", "Math"]
sbs['C08-Math'] = ["Literature", "Chemistry", "Biology", "Math"]
sbs['C09-Math'] = ["Literature", "Physics", "Geography", "Math"]
sbs['C10-Math'] = ["Literature", "Chemistry", "History", "Math"]
sbs['C12-Math'] = ["Literature", "Biology", "History", "Math"]
sbs['C13-Math'] = ["Literature", "Biology", "Geography", "Math"]
sbs['C14-Math'] = ["Literature", "Math", "Civic Education", "Math"]
sbs['C16-Math'] = ["Literature", "Physics", "Civic Education", "Math"]
sbs['C17-Math'] = ["Literature", "Chemistry", "Civic Education", "Math"]
sbs['C19-Math'] = ["Literature", "History", "Civic Education", "Math"]
sbs['C20-Math'] = ["Literature", "Geography", "Civic Education", "Math"]
sbs['D01-Math'] = ["Literature", "Math", "English", "Math"]
sbs['D07-Math'] = ["Math", "Chemistry", "English", "Math"]
sbs['D08-Math'] = ["Math", "Biology", "English", "Math"]
sbs['D09-Math'] = ["Math", "History", "English", "Math"]
sbs['D10-Math'] = ["Math", "Geography", "English", "Math"]
sbs['D11-Math'] = ["Literature", "Physics", "English", "Math"]
sbs['D12-Math'] = ["Literature", "Chemistry", "English", "Math"]
sbs['D13-Math'] = ["Literature", "Biology", "English", "Math"]
sbs['D14-Math'] = ["Literature", "History", "English", "Math"]
sbs['D15-Math'] = ["Literature", "Geography", "English", "Math"]
sbs['D66-Math'] = ["Literature", "Civic Education", "English", "Math"]
sbs['D84-Math'] = ["Math", "Civic Education", "English", "Math"]
sbs['A00-English'] = ["Math", "Physics", "Chemistry", "English"]
sbs['A01-English'] = ["Math", "Physics", "English", "English"]
sbs['A02-English'] = ["Math", "Physics", "Biology", "English"]
sbs['A03-English'] = ["Math", "Physics", "History", "English"]
sbs['A04-English'] = ["Math", "Physics", "Geography", "English"]
sbs['A05-English'] = ["Math", "Chemistry", "History", "English"]
sbs['A06-English'] = ["Math", "Chemistry", "Geography", "English"]
sbs['A07-English'] = ["Math", "History", "Geography", "English"]
sbs['A08-English'] = ["Math", "History", "Civic Education", "English"]
sbs['A09-English'] = ["Math", "Geography", "Civic Education", "English"]
sbs['A10-English'] = ["Math", "Physics", "Civic Education", "English"]
sbs['A11-English'] = ["Math", "Chemistry", "Civic Education", "English"]
sbs['B00-English'] = ["Math", "Chemistry", "Biology", "English"]
sbs['B01-English'] = ["Math", "Biology", "History", "English"]
sbs['B02-English'] = ["Math", "Biology", "Geography", "English"]
sbs['B03-English'] = ["Math", "Biology", "Literature", "English"]
sbs['B04-English'] = ["Math", "Biology", "Civic Education", "English"]
sbs['B08-English'] = ["Math", "Biology", "English", "English"]
sbs['C00-English'] = ["Literature", "History", "Geography", "English"]
sbs['C01-English'] = ["Literature", "Math", "Physics", "English"]
sbs['C02-English'] = ["Literature", "Math", "Chemistry", "English"]
sbs['C03-English'] = ["Literature", "Math", "History", "English"]
sbs['C04-English'] = ["Literature", "Math", "Geography", "English"]
sbs['C05-English'] = ["Literature", "Physics", "Chemistry", "English"]
sbs['C06-English'] = ["Literature", "Physics", "Biology", "English"]
sbs['C07-English'] = ["Literature", "Physics", "History", "English"]
sbs['C08-English'] = ["Literature", "Chemistry", "Biology", "English"]
sbs['C09-English'] = ["Literature", "Physics", "Geography", "English"]
sbs['C10-English'] = ["Literature", "Chemistry", "History", "English"]
sbs['C12-English'] = ["Literature", "Biology", "History", "English"]
sbs['C13-English'] = ["Literature", "Biology", "Geography", "English"]
sbs['C14-English'] = ["Literature", "Math", "Civic Education", "English"]
sbs['C16-English'] = ["Literature", "Physics", "Civic Education", "English"]
sbs['C17-English'] = ["Literature", "Chemistry", "Civic Education", "English"]
sbs['C19-English'] = ["Literature", "History", "Civic Education", "English"]
sbs['C20-English'] = ["Literature", "Geography", "Civic Education", "English"]
sbs['D01-English'] = ["Literature", "Math", "English", "English"]
sbs['D07-English'] = ["Math", "Chemistry", "English", "English"]
sbs['D08-English'] = ["Math", "Biology", "English", "English"]
sbs['D09-English'] = ["Math", "History", "English", "English"]
sbs['D10-English'] = ["Math", "Geography", "English", "English"]
sbs['D11-English'] = ["Literature", "Physics", "English", "English"]
sbs['D12-English'] = ["Literature", "Chemistry", "English", "English"]
sbs['D13-English'] = ["Literature", "Biology", "English", "English"]
sbs['D14-English'] = ["Literature", "History", "English", "English"]
sbs['D15-English'] = ["Literature", "Geography", "English", "English"]
sbs['D66-English'] = ["Literature", "Civic Education", "English", "English"]
sbs['D84-English'] = ["Math", "Civic Education", "English", "English"]
len(sbs)
Out[4]:
144
In [5]:
# Compute grades for each subjects combination
for year in grades:
  for sb in sbs:
    grades[year][sb] = 0
    for x in sbs[sb]:
      grades[year][sb] = grades[year][sb] + grades[year][x]
    grades[year][sb] *= 3/len(sbs[sb]) # Normalizing
display(grades[2021])
/var/folders/ln/rz3xh60x0zbb7cfm8z1lrlm40000gn/T/ipykernel_81835/148978670.py:4: PerformanceWarning: DataFrame is highly fragmented.  This is usually the result of calling `frame.insert` many times, which has poor performance.  Consider joining all columns at once using pd.concat(axis=1) instead.  To get a de-fragmented frame, use `newframe = frame.copy()`
  grades[year][sb] = 0
ID CityCode CityArea Math Literature English Physics Chemistry Biology Geography ... D08-English D09-English D10-English D11-English D12-English D13-English D14-English D15-English D66-English D84-English
0 1000001 1 1.0 2.2 3.50 NaN NaN NaN NaN 5.50 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 1000002 1 1.0 9.2 8.25 10.0 NaN NaN NaN 9.75 ... NaN 26.2125 29.2125 NaN NaN NaN 25.5000 28.5000 28.1250 28.8375
2 1000003 1 1.0 4.4 6.25 NaN NaN NaN NaN 4.00 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 1000004 1 1.0 8.4 6.75 10.0 4.00 3.00 3.50 NaN ... 23.9250 NaN NaN 23.0625 22.3125 22.6875 NaN NaN NaN NaN
4 1000005 1 1.0 8.8 8.25 9.4 8.25 5.75 5.25 NaN ... 24.6375 NaN NaN 26.4750 24.6000 24.2250 NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1002265 64006834 64 6.0 8.6 8.25 6.2 8.25 7.00 6.50 NaN ... 20.6250 NaN NaN 21.6750 20.7375 20.3625 NaN NaN NaN NaN
1002266 64006835 64 6.0 9.0 7.50 9.4 8.00 8.25 5.50 NaN ... 24.9750 NaN NaN 25.7250 25.9125 23.8500 NaN NaN NaN NaN
1002267 64006836 64 6.0 4.8 7.00 4.6 NaN NaN NaN 7.00 ... NaN 13.3125 15.7500 NaN NaN NaN 14.9625 17.4000 18.9000 17.2500
1002268 64006837 64 6.0 7.4 7.75 9.4 NaN NaN NaN 6.75 ... NaN 23.0250 24.7125 NaN NaN NaN 23.2875 24.9750 26.8500 26.5875
1002269 64006838 64 6.0 8.0 7.75 8.2 NaN NaN NaN 6.50 ... NaN 21.4875 23.1750 NaN NaN NaN 21.3000 22.9875 23.7375 23.9250

1002270 rows × 156 columns

In [6]:
# Read standard grades
standard_grades = {}
for year in range(2018, 2022):
  standard_grades[year] = pd.read_csv(f'{data_path}/standard_grades_{year}.csv')
  standard_grades[year]['Main Subject'] = standard_grades[year]['Main Subject'].fillna("")
display(standard_grades[2021])
Major ID Major Subjects Combination Standard Grade Main Subject
0 BF1 Kỹ thuật Sinh học A00, B00 25.34 Math
1 BF2 Kỹ thuật Thực phẩm A00, B00 25.94 Math
2 CH1 Kỹ thuật Hóa học A00, B00, D07 25.20 Math
3 CH2 Hóa học A00, B00, D07 24.96 Math
4 CH3 Kỹ thuật In A00, B00, D07 24.45 Math
5 ED2 Công nghệ Giáo dục A00, A01, D01 24.80
6 EE1 Kỹ thuật Điện A00, A01 26.50
7 EE2 Kỹ thuật Điều khiển và Tự động hóa A00, A01 27.46 Math
8 EM1 Kinh tế Công nghiệp A00, A01, D01 25.65
9 EM2 Quản lý Công nghiệp A00, A01, D01 25.75
10 EM3 Quản trị Kinh doanh A00, A01, D01 26.04
11 EM4 Kế toán A00, A01, D01 25.76
12 EM5 Tài chính Ngân hàng A00, A01, D01 25.83
13 ET1 Kỹ thuật Điện tử Viễn thông A00, A01 26.80 Math
14 EV1 Kỹ thuật Môi trường A00, B00, D07 24.01 Math
15 EV2 Quản lý Tài nguyên và Môi trường* A00, B00, D07 23.53
16 FL1 Tiếng Anh KHKT và Công nghệ D01 26.39 English
17 FL2 Tiếng Anh chuyên nghiệp quốc tế D01 26.11 English
18 HE1 Kỹ thuật Nhiệt A00, A01 24.50 Math
19 IT1 Khoa học Máy tính A00, A01 28.43 Math
20 IT2 Kỹ thuật Máy tính A00, A01 28.10 Math
21 ME1 Kỹ thuật Cơ điện tử A00, A01 26.91 Math
22 ME2 Kỹ thuật Cơ khí A00, A01 25.78 Math
23 MI1 Toán Tin A00, A01 27.00 Math
24 MI2 Hệ thống thông tin quản lý A00, A01 27.00 Math
25 MS1 Kỹ thuật Vật liệu A00, A01, D07 24.65 Math
26 PH1 Vật lý Kỹ thuật A00, A01, A02 25.64 Math
27 PH2 Kỹ thuật Hạt nhân A00, A01, A02 24.48 Math
28 PH3 Vật lý Y khoa* A00, A01, A02 25.36
29 TE1 Kỹ thuật Ô tô A00, A01 26.94 Math
30 TE2 Kỹ thuật Cơ khí động lực A00, A01 25.70 Math
31 TE3 Kỹ thuật Hàng không A00, A01 26.48 Math
32 TX1 Kỹ thuật Dệt May A00, A01 23.99 Math
33 BF-E12 Kỹ thuật Thực phẩm (Chương trình tiên tiến) A00, B00 24.44 Math
34 CH-E11 Kỹ thuật Hóa dược (Chương trình tiên tiến) A00, B00, D07 26.40 Math
35 EE-E18 Hệ thống điện và năng lượng tái tạo (Chương tr... A00, A01 25.71
36 EE-E8 Kỹ thuật điều khiển Tự động hóa (Chương trình ... A00, A01 27.26 Math
37 EE-EP Tin học công nghiệp và Tự động hóa (Chương trì... A00, A01, D29 26.14 Math
38 EM-E13 Phân tích Kinh doanh (Chương trình tiên tiến) D07, A01, D01 25.55 Math
39 EM-E14 Logistics và Quản lý chuỗi cung ứng (Chương tr... D07, A01, D01 26.33
40 ET-E4 Kỹ thuật Điện tử Viễn thông (Chương trình tiên... A00, A01 26.59 Math
41 ET-E5 Kỹ thuật Y sinh (Chương trình tiên tiến) A00, A01 25.88 Math
42 ET-E9 Hệ thống nhúng thông minh và IoT (Chương trình... A00, A01, D28 26.93 Math
43 ET-E16 Truyền thông số và Kỹ thuật đa phương tiện (Ch... A00, A01 26.59
44 IT-E6 Công nghệ Thông tin Việt-Nhật (Chương trình ti... A00, A01, D28 27.40 Math
45 IT-E7 Công nghệ Thông tin Global ICT (Chương trình t... A00, A01 27.85 Math
46 IT-E10 Khoa học Dữ liệu và Trí tuệ nhân tạo (Chương t... A00, A01 28.04 Math
47 IT-E15 An toàn không gian số* (Chương trình tiên tiến) A00, A01 27.44
48 IT-EP Công nghệ Thông tin Việt-Pháp (Chương trình ti... A00, A01, D29 27.19 Math
49 ME-E1 Kỹ thuật Cơ điện tử (Chương trình tiên tiến) A00, A01 26.30 Math
50 MS-E3 KHKT Vật liệu (Chương trình tiên tiến) A00, A01 23.99 Math
51 TE-E2 Kỹ thuật Ô tô (Chương trình tiên tiến) A00, A01 26.11 Math
52 TE-EP Cơ khí Hàng không Việt-Pháp (Chương trình tiên... A00, A01, D29 24.76 Math
53 ET-LUH Điện tử Viễn thông-Leibniz Hannover (Đức) A00, A01, D26 25.13
54 ME-GU Cơ khí Chế tạo máy-Griffith (Úc) A00, A01 23.88
55 ME-LUH Cơ điện tử-Leibniz Hannover (Đức) A00, A01, D26 25.16
56 ME-NUT Cơ điện tử-Nagaoka (Nhật Bản) A00, A01, D28 24.88
57 TROY-BA Quản trị Kinh doanh-Troy (Hoa Kỳ) A00, A01, D01 23.25
58 TROY-IT Khoa học Máy tính-Troy (Hoa Kỳ) A00, A01, D01 25.50
In [7]:
yearS, yearT = 2020, 2021
# Get real grades of target year
data = standard_grades[yearT]
real_grades = {}
for x, y in data.iterrows():
  z = list(y.values)
  real_grades[z[0]] = z[3]
print(real_grades)

# Add real grades columns to source year table
data = standard_grades[yearS]
new_col = []
for x, y in data.iterrows():
  z = list(y)
  if z[0] in real_grades:
    new_col.append(real_grades[z[0]])
  else:
    new_col.append(float("NaN"))
standard_grades[yearS][f'Real Grades {yearT}'] = new_col
display(standard_grades[yearS].transpose())
{'BF1': 25.34, 'BF2': 25.94, 'CH1': 25.2, 'CH2': 24.96, 'CH3': 24.45, 'ED2': 24.8, 'EE1': 26.5, 'EE2': 27.46, 'EM1': 25.65, 'EM2': 25.75, 'EM3': 26.04, 'EM4': 25.76, 'EM5': 25.83, 'ET1': 26.8, 'EV1': 24.01, 'EV2': 23.53, 'FL1': 26.39, 'FL2': 26.11, 'HE1': 24.5, 'IT1': 28.43, 'IT2': 28.1, 'ME1': 26.91, 'ME2': 25.78, 'MI1': 27.0, 'MI2': 27.0, 'MS1': 24.65, 'PH1': 25.64, 'PH2': 24.48, 'PH3': 25.36, 'TE1': 26.94, 'TE2': 25.7, 'TE3': 26.48, 'TX1': 23.99, 'BF-E12': 24.44, 'CH-E11': 26.4, 'EE-E18': 25.71, 'EE-E8': 27.26, 'EE-EP': 26.14, 'EM-E13': 25.55, 'EM-E14': 26.33, 'ET-E4': 26.59, 'ET-E5': 25.88, 'ET-E9': 26.93, 'ET-E16': 26.59, 'IT-E6': 27.4, 'IT-E7': 27.85, 'IT-E10': 28.04, 'IT-E15': 27.44, 'IT-EP': 27.19, 'ME-E1': 26.3, 'MS-E3': 23.99, 'TE-E2': 26.11, 'TE-EP': 24.76, 'ET-LUH': 25.13, 'ME-GU': 23.88, 'ME-LUH': 25.16, 'ME-NUT': 24.88, 'TROY-BA': 23.25, 'TROY-IT': 25.5}
0 1 2 3 4 5 6 7 8 9 ... 47 48 49 50 51 52 53 54 55 56
Major ID BF1 BF2 BF-E12 CH1 CH2 CH3 CH-E11 ED2 ΕΕ1 EE2 ... PH1 PH2 TE1 TE2 TE3 TE-E2 TE-EP TROY-BA TROY-IT TX1
Major Kỹ thuật Sinh học Kỹ thuật Thực phẩm Kỹ thuật Thực phẩm (CT tiên tiến) Kỹ thuật Hoá học Hoá học Kỹ thuật in Kỹ thuật Hóa dược (CT tiên tiến) Công nghệ giáo dục Kỹ thuật Điện Kỹ thuật Điều khiển - Tự động hoá ... Vật lý kỹ thuật Kỹ thuật hạt nhân Kỹ thuật Ô tô Kỹ thuật Cơ khí động lực Kỹ thuật Hàng không Kỹ thuật Ô tô (CT tiên tiến) Cơ khí hàng không (Chương trình Việt - Pháp PF... Quản trị kinh doanh - hợp tác với ĐH Troy (Hoa... Khoa học máy tính - hợp tác với ĐH Troy (Hoa Ký) Kỹ thuật Dệt - May
Subjects Combination A00, B00, D07 A00, B00, D07 A00, B00, D07 A00, A01, B00, D07 A00, A01, B00, D07 A00, A01, B00, D07 A00, A01, B00, D07 A00, A01, D01 A00, A01 A00, A01 ... A00, A01 A00, A01, A02 A00, A01 A00, A01 A00, A01 A00, A01 A00, A01, D29 A00, A01, D01 A00, A01, D01 A00, A01, D07
Standard Grade 26.2 26.6 25.94 25.26 24.16 24.51 26.5 23.8 27.01 28.16 ... 26.18 24.7 27.33 26.46 26.94 26.75 23.88 22.5 25.0 23.04
Main Subject Math Math Math Math Math Math Math Math Math ... Math Math Math Math Math Math Math Math
Real Grades 2021 25.34 25.94 24.44 25.2 24.96 24.45 26.4 24.8 NaN 27.46 ... 25.64 24.48 26.94 25.7 26.48 26.11 24.76 23.25 25.5 23.99

6 rows × 57 columns

In [8]:
# Return maximum grade of lowest p% candidates in given subjects combination list
def get_point(percentage, year, subjects_combination):
  data = grades[year][subjects_combination].max(1)
  data = [round(x,2) for x in data if not np.isnan(x)]
  data = sorted(data)
  if len(data) == 0: # Return 0 if not valid any candidates
    return 0
  return data[min(len(data)-1, floor(len(data)*percentage/100))]
In [9]:
# Return percentage range of given point
eps = 0.3 # (point-eps -> point+eps)
def get_percentage(point, year, subjects_combination):
  subjects_combination = [x for x in subjects_combination if x in list(grades[year].head())]
  data = grades[year][subjects_combination].max(1)
  data = [round(x,2) for x in data if not np.isnan(x)]
  data = sorted(data)
  if len(data) == 0: # Return (0, 0) if not valid any candidates
    return 0, 0
  return bisect_left(data, point-eps)/len(data)*100, bisect_right(data, point+eps)/len(data)*100
In [10]:
# Exchange point between source year and target year in given subjects combination list
def exchange(point, yearS, yearT, subjects_combination):
  subjects_combination = [x for x in subjects_combination if x in list(grades[year].head())]
  percentage = get_percentage(point, yearS, subjects_combination)
  return get_point(percentage[0], yearT, subjects_combination), get_point(percentage[1], yearT, subjects_combination)
In [11]:
exchange(20, 2018, 2021, ['A00'])
Out[11]:
(24.4, 24.8)
In [12]:
# Return list of converted grades from source year to target year
def convert_grades(yearS, yearT):
  new_col_1 = []
  new_col_2 = []
  for x, y in standard_grades[yearS].iterrows():
    z = list(y.values)
    t = z[2].replace(',', '').split()
    if z[4]:
      t = [u + '-' + z[4] for u in t]
    t = exchange(z[3], yearS, yearT, t)
    print(f"[{x+1}\\{len(standard_grades[yearS])}]\t{z[0]}\t{yearS}\t{z[3]}\t{yearT}\t{z[-1]}\t{t}")
    new_col_1.append(t[0])
    new_col_2.append(t[1])
  return new_col_1, new_col_2

results = convert_grades(yearS, yearT)
standard_grades[yearS][f'Predicted Grades Lower {yearT}'] = results[0]
standard_grades[yearS][f'Predicted Grades Upper {yearT}'] = results[1]
[1\57]	BF1	2020	26.2	2021	25.34	(25.61, 26.14)
[2\57]	BF2	2020	26.6	2021	25.94	(25.99, 26.55)
[3\57]	BF-E12	2020	25.94	2021	24.44	(25.35, 25.91)
[4\57]	CH1	2020	25.26	2021	25.2	(24.9, 25.46)
[5\57]	CH2	2020	24.16	2021	24.96	(23.89, 24.45)
[6\57]	CH3	2020	24.51	2021	24.45	(24.19, 24.75)
[7\57]	CH-E11	2020	26.5	2021	26.4	(26.06, 26.62)
[8\57]	ED2	2020	23.8	2021	24.8	(24.25, 24.75)
[9\57]	ΕΕ1	2020	27.01	2021	nan	(26.48, 27.08)
[10\57]	EE2	2020	28.16	2021	27.46	(27.56, 28.16)
[11\57]	EE-E8	2020	27.43	2021	27.26	(26.89, 27.49)
[12\57]	EE-EP	2020	25.68	2021	26.14	(25.2, 25.76)
[13\57]	EM1	2020	24.65	2021	25.65	(24.95, 25.45)
[14\57]	EM2	2020	25.05	2021	25.75	(25.25, 25.8)
[15\57]	EM3	2020	25.75	2021	26.04	(25.85, 26.4)
[16\57]	EM4	2020	25.3	2021	25.76	(25.45, 26.0)
[17\57]	EM5	2020	24.6	2021	25.83	(24.9, 25.45)
[18\57]	EM-E13	2020	25.03	2021	25.55	(24.6, 25.16)
[19\57]	EM-E14	2020	25.85	2021	26.33	(25.95, 26.45)
[20\57]	EM-VUW	2020	22.7	2021	nan	(23.35, 23.85)
[21\57]	ET1	2020	27.3	2021	26.8	(26.74, 27.38)
[22\57]	ET-E4	2020	27.15	2021	26.59	(26.62, 27.22)
[23\57]	ET-E5	2020	26.5	2021	25.88	(25.99, 26.55)
[24\57]	ET-E9	2020	27.51	2021	26.93	(26.96, 27.56)
[25\57]	ET-LUH	2020	23.85	2021	25.13	(23.6, 24.25)
[26\57]	EV1	2020	23.85	2021	24.01	(23.55, 24.15)
[27\57]	FL1	2020	24.1	2021	26.39	(25.72, 26.1)
[28\57]	FL2	2020	24.1	2021	26.11	(25.72, 26.1)
[29\57]	HE1	2020	25.8	2021	24.5	(25.31, 25.91)
[30\57]	IT1	2020	29.04	2021	28.43	(28.46, 29.14)
[31\57]	IT2	2020	28.65	2021	28.1	(28.01, 28.69)
[32\57]	IT-E10	2020	28.65	2021	28.04	(28.01, 28.69)
[33\57]	IT-E6	2020	27.98	2021	27.4	(27.41, 28.01)
[34\57]	IT-E7	2020	28.38	2021	27.85	(27.79, 28.39)
[35\57]	IT-EP	2020	27.24	2021	27.19	(26.74, 27.3)
[36\57]	IT-LTU	2020	26.5	2021	nan	(26.15, 26.75)
[37\57]	IT-VUW	2020	25.55	2021	nan	(25.25, 25.85)
[38\57]	ME1	2020	27.48	2021	26.91	(26.92, 27.49)
[39\57]	ME2	2020	26.51	2021	25.78	(25.99, 26.62)
[40\57]	ME-E1	2020	26.75	2021	26.3	(26.25, 26.81)
[41\57]	ME-GU	2020	23.9	2021	23.88	(23.65, 24.3)
[42\57]	ME-LUH	2020	24.2	2021	25.16	(23.95, 24.6)
[43\57]	ME-NUT	2020	24.5	2021	24.88	(24.25, 24.9)
[44\57]	MI1	2020	27.56	2021	27.0	(27.0, 27.6)
[45\57]	MI2	2020	27.25	2021	27.0	(26.74, 27.3)
[46\57]	MS1	2020	25.18	2021	24.65	(24.86, 25.42)
[47\57]	MS-E3	2020	23.18	2021	23.99	(22.95, 23.55)
[48\57]	PH1	2020	26.18	2021	25.64	(25.65, 26.29)
[49\57]	PH2	2020	24.7	2021	24.48	(24.26, 24.83)
[50\57]	TE1	2020	27.33	2021	26.94	(26.78, 27.38)
[51\57]	TE2	2020	26.46	2021	25.7	(25.95, 26.55)
[52\57]	TE3	2020	26.94	2021	26.48	(26.44, 27.0)
[53\57]	TE-E2	2020	26.75	2021	26.11	(26.25, 26.81)
[54\57]	TE-EP	2020	23.88	2021	24.76	(23.48, 24.07)
[55\57]	TROY-BA	2020	22.5	2021	23.25	(23.15, 23.7)
[56\57]	TROY-IT	2020	25.0	2021	25.5	(25.2, 25.75)
[57\57]	TX1	2020	23.04	2021	23.99	(22.84, 23.44)
In [13]:
# Display prediction
standard_grades[yearS] = standard_grades[yearS].sort_values(['Standard Grade'])
features = [f'Real Grades {yearT}', f'Predicted Grades Lower {yearT}', f'Predicted Grades Upper {yearT}']
data = standard_grades[yearS][['Major ID'] + features].copy()
data = data.dropna()
data = data[data[f'Predicted Grades Lower {yearT}']>=0]
# data = data.sort_values([f'Predicted Grades Lower {yearT}'])
data = data.set_index('Major ID')
rows = []
for x, y in data.iterrows():
  for feature in features:
    rows.append([x, feature, y[feature]])
data = pd.DataFrame(rows, columns = ["Major ID", "Type", "Grade"])
display(data.transpose())
import plotly.express as px
fig = px.line(data, x='Major ID', y='Grade', color='Type', title="Hanoi University of Science & Technology (HUST) - Standard Passing Grades".upper())
fig.show()
0 1 2 3 4 5 6 7 8 9 ... 149 150 151 152 153 154 155 156 157 158
Major ID TROY-BA TROY-BA TROY-BA TX1 TX1 TX1 MS-E3 MS-E3 MS-E3 ED2 ... IT-E7 IT-E10 IT-E10 IT-E10 IT2 IT2 IT2 IT1 IT1 IT1
Type Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 ... Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021
Grade 23.25 23.15 23.7 23.99 22.84 23.44 23.99 22.95 23.55 24.8 ... 28.39 28.04 28.01 28.69 28.1 28.01 28.69 28.43 28.46 29.14

3 rows × 159 columns

In [14]:
# Display prediction
standard_grades[yearS] = standard_grades[yearS].sort_values([f'Predicted Grades Lower {yearT}'])
features = [f'Real Grades {yearT}', f'Predicted Grades Lower {yearT}', f'Predicted Grades Upper {yearT}']
data = standard_grades[yearS][['Major ID'] + features].copy()
data = data.dropna()
data = data[data[f'Predicted Grades Lower {yearT}']>=0]
# data = data.sort_values([f'Predicted Grades Lower {yearT}'])
data = data.set_index('Major ID')
rows = []
for x, y in data.iterrows():
  for feature in features:
    rows.append([x, feature, y[feature]])
data = pd.DataFrame(rows, columns = ["Major ID", "Type", "Grade"])
display(data.transpose())
data.to_csv(f'exchange-grade-{yearS}-{yearT}.csv')  
import plotly.express as px
fig = px.line(data, x='Major ID', y='Grade', color='Type', title="Hanoi University of Science & Technology (HUST) - Standard Passing Grades".upper())
fig.show()
0 1 2 3 4 5 6 7 8 9 ... 149 150 151 152 153 154 155 156 157 158
Major ID TX1 TX1 TX1 MS-E3 MS-E3 MS-E3 TROY-BA TROY-BA TROY-BA TE-EP ... IT-E7 IT-E10 IT-E10 IT-E10 IT2 IT2 IT2 IT1 IT1 IT1
Type Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 ... Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021
Grade 23.99 22.84 23.44 23.99 22.95 23.55 23.25 23.15 23.7 24.76 ... 28.39 28.04 28.01 28.69 28.1 28.01 28.69 28.43 28.46 29.14

3 rows × 159 columns

In [15]:
# Display prediction
standard_grades[yearS] = standard_grades[yearS].sort_values([f'Real Grades {yearT}'])
features = [f'Real Grades {yearT}', f'Predicted Grades Lower {yearT}', f'Predicted Grades Upper {yearT}']
data = standard_grades[yearS][['Major ID'] + features].copy()
data = data.dropna()
data = data[data[f'Predicted Grades Lower {yearT}']>=0]
# data = data.sort_values([f'Predicted Grades Lower {yearT}'])
data = data.set_index('Major ID')
rows = []
for x, y in data.iterrows():
  for feature in features:
    rows.append([x, feature, y[feature]])
data = pd.DataFrame(rows, columns = ["Major ID", "Type", "Grade"])
display(data.transpose())  
import plotly.express as px
fig = px.line(data, x='Major ID', y='Grade', color='Type', title="Hanoi University of Science & Technology (HUST) - Standard Passing Grades".upper())
fig.show()
0 1 2 3 4 5 6 7 8 9 ... 149 150 151 152 153 154 155 156 157 158
Major ID TROY-BA TROY-BA TROY-BA ME-GU ME-GU ME-GU TX1 TX1 TX1 MS-E3 ... IT-E7 IT-E10 IT-E10 IT-E10 IT2 IT2 IT2 IT1 IT1 IT1
Type Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 ... Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021 Real Grades 2021 Predicted Grades Lower 2021 Predicted Grades Upper 2021
Grade 23.25 23.15 23.7 23.88 23.65 24.3 23.99 22.84 23.44 23.99 ... 28.39 28.04 28.01 28.69 28.1 28.01 28.69 28.43 28.46 29.14

3 rows × 159 columns